using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using Alchemi.Core.Owner;
using System.Windows.Forms;
using Renderer.DataStructures;
using Renderer.Utils;

namespace Renderer
{
    public partial class MainForm : Form
    {
        private readonly int ROW_NUM = 2;
        private readonly int COL_NUM = 2;
        private readonly string SCENE_FILENAME = "Resources/scene.txt";
        private Bitmap image;
        private GApplication ga;
        private ISceneLoader sceneLoader = new SimpleSceneLoader();
                
        public MainForm()
        {
            InitializeComponent();
        }


        private void MainForm_Load(object sender, EventArgs ev)
        {            
            Logger.Log("Loading.");
            
            try
            {
                image = new Bitmap(Image.FromFile("Resources/background.jpg"));
                pictureBox.Image = image;

                ga = new GApplication();
//                GConnectionDialog gcd = new GConnectionDialog();                
//
//                if (gcd.ShowDialog() == DialogResult.OK)
//                {
                    // initialise application
                    ga = new GApplication();
                    ga.ApplicationName = "Renderer";

                    //ga.Connection = gcd.Connection;
                    ga.Connection = new GConnection("localhost", 9000, "user", "user");

                    // set dependencies
                    ga.Manifest.Add(new EmbeddedFileDependency("helena.jpg", "Resources/helena.jpg"));
                    ga.Manifest.Add(new ModuleDependency(typeof(RendererThread).Module));

                    // subscribe to events
                    ga.ThreadFinish += new GThreadFinish(UpdateScreen);
                    ga.ApplicationFinish += new GApplicationFinish(AppDone);
//                }
//                else
//                {
//                    return;
//                }


                Scene scene = sceneLoader.LoadScene(SCENE_FILENAME);
                
                for (int i = 0; i < ROW_NUM; i++)
                {
                    for (int j = 0; j < COL_NUM; j++)
                    {
                        // create render thread and pass into it the whole scene and 
                        // coordinates and size of the part of the screen to render                        
                        RendererThread thread;
                        thread =
                            new RendererThread(scene,
                                               i, j,
                                               new Rectangle(0, 0, pictureBox.Width/COL_NUM, pictureBox.Height/ROW_NUM),
                                               new Rectangle(0, 0, pictureBox.Width, pictureBox.Height));
                        ga.Threads.Add(thread);
                    }
                }

                Logger.Log("Starting.");
                ga.Start();                
            }
            catch (Exception e)
            {
                ExceptionHandler.Handle(e);
                Logger.Log("Not started.");
                return;
            }
            Logger.Log("Started.");
        }
        
        public void UpdateScreen(GThread thread)
        {            
            RendererThread th = (RendererThread)thread;
            int height = pictureBox.Height / ROW_NUM;
            int width = pictureBox.Width / COL_NUM;
            int startI = th.Row * height;
            int startJ = th.Col * width;
            Bitmap result = th.ResultPicure;
            Logger.Log("In Update Screen: startI=" + startI + "; startJ=" + startJ + "; height=" + height + "; width=" + width);
            
            for (int i = startI; i < startI + height; i++)
            {
                for (int j = startJ; j < startJ + width; j++)
                {
                    if (i - startI < result.Height && j - startJ < result.Width)
                    {
                        image.SetPixel(j, i, result.GetPixel(j - startJ,i - startI));                        
                    }
                }
                pictureBox.BeginInvoke(new Delegate(pictureBox.Refresh));
            }            
        }
        
        public delegate void Delegate();
        
        void AppDone()
        {
            Logger.Log("Application finished");            
        }
    }
}